﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using log4net;

namespace MyLib.Web.UI {
	/// <summary>
	/// 
	/// </summary>
	[DefaultProperty("Title")]
	[DefaultEvent("Saved")]
	[SupportsEventValidation]
	[Designer(typeof(MyFormViewDesigner))]
	[ToolboxData("<{0}:MyFormView runat=\"server\"><ContentTemplate></ContentTemplate></{0}:MyFormView>")]
	public class MyFormView : CompositeDataBoundControl, IDataItemContainer, IDataBoundItemControl, INamingContainer, IPostBackEventHandler, IPostBackContainer {
		#region Private fields
		private ILog m_logger = LogManager.GetLogger(typeof(MyFormView));

		private object m_dataItem;

		private IOrderedDictionary m_saveKeys;

		private IOrderedDictionary m_saveOldValues;

		private IOrderedDictionary m_saveNewValues;

		private IOrderedDictionary m_boundFields;

		private DataKey m_dataKey;

		private OrderedDictionary m_keyTable;

		private string[] m_dataKeyNames;

		private Style m_titleBarStyle;

		private Style m_titleStyle;

		private Style m_contentStyle;

		#endregion

		/// <summary>
		/// 
		/// </summary>
		[Bindable(true)]
		[Category("Accessibility")]
		[DefaultValue("")]
		public string Title {
			get {
				var obj = ViewState["Title"];
				if (obj == null) {
					return "";
				} else {
					return (string)obj;
				}
			}
			set {
				ViewState["Title"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Bindable(false)]
		[Category("Accessibility")]
		[DefaultValue("")]
		public string ErrorMessageFormat {
			get {
				var obj = ViewState["ErrorMessageFormat"];
				if (obj == null) {
					return "";
				} else {
					return (string)obj;
				}
			}
			set {
				ViewState["ErrorMessageFormat"] = value;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Browsable(false)]
		[Category("Appearance")]
		[DefaultValue("")]
		[TemplateContainer(typeof(MyFormView))]
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public ITemplate EmptyDataTemplate { get; set; }

		/// <summary>
		/// 
		/// </summary>
		[Browsable(false)]
		[Category("Appearance")]
		[DefaultValue("")]
		[TemplateContainer(typeof(MyFormView), System.ComponentModel.BindingDirection.TwoWay)]
		[PersistenceMode(PersistenceMode.InnerProperty)]
		public ITemplate ContentTemplate { get; set; }

		/// <summary>
		/// 
		/// </summary>
		[Description("MyPanel_EmptyStyle"),
		NotifyParentProperty(true),
		Category("Styles"), DefaultValue((string)null),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		PersistenceMode(PersistenceMode.InnerProperty)]
		public Style EmptyStyle {
			get {
				if (this.m_titleBarStyle == null) {
					this.m_titleBarStyle = new Style();
					if (base.IsTrackingViewState) {
						((IStateManager)this.m_titleBarStyle).TrackViewState();
					}
				}
				return this.m_titleBarStyle;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Description("MyPanel_TitleBarStyle"),
		NotifyParentProperty(true),
		Category("Styles"), DefaultValue((string)null),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		PersistenceMode(PersistenceMode.InnerProperty)]
		public Style TitleBarStyle {
			get {
				if (this.m_titleBarStyle == null) {
					this.m_titleBarStyle = new Style();
					if (base.IsTrackingViewState) {
						((IStateManager)this.m_titleBarStyle).TrackViewState();
					}
				}
				return this.m_titleBarStyle;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[Description("MyPanel_TitleStyle"),
		NotifyParentProperty(true),
		Category("Styles"), DefaultValue((string)null),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		PersistenceMode(PersistenceMode.InnerProperty)]
		public Style TitleStyle {
			get {
				if (this.m_titleStyle == null) {
					this.m_titleStyle = new Style();
					if (base.IsTrackingViewState) {
						((IStateManager)this.m_titleStyle).TrackViewState();
					}
				}
				return this.m_titleStyle;
			}
		}


		/// <summary>
		/// 
		/// </summary>
		[Description("MyPanel_ContentStyle"),
		NotifyParentProperty(true),
		Category("Styles"), DefaultValue((string)null),
		DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
		PersistenceMode(PersistenceMode.InnerProperty)]
		public Style ContentStyle {
			get {
				if (this.m_contentStyle == null) {
					this.m_contentStyle = new Style();
					if (base.IsTrackingViewState) {
						((IStateManager)this.m_contentStyle).TrackViewState();
					}
				}
				return this.m_contentStyle;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		private string[] DataKeyNamesInternal {
			get {
				if (this.m_dataKeyNames != null) {
					return this.m_dataKeyNames;
				}
				return new string[0];
			}
		}

		/// <summary>
		/// 
		/// </summary>
		private OrderedDictionary KeyTable {
			get {
				if (this.m_keyTable == null) {
					this.m_keyTable = new OrderedDictionary(this.DataKeyNamesInternal.Length);
				}
				return this.m_keyTable;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected override void OnInit(EventArgs e) {
			base.OnInit(e);

			if (Page != null) {
				Page.RegisterRequiresControlState(this);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected override HtmlTextWriterTag TagKey {
			get {
				return HtmlTextWriterTag.Div;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dataSource"></param>
		/// <param name="dataBinding"></param>
		/// <returns></returns>
		protected override int CreateChildControls(System.Collections.IEnumerable dataSource, bool dataBinding) {
			var hasData = false;
			IEnumerator enumerator = null;

			if (dataSource != null) {
				enumerator = dataSource.GetEnumerator();
				if (enumerator != null) {
					hasData = enumerator.MoveNext();
				}
			}

			if (!hasData) {
				if (EmptyDataTemplate != null) {
					EmptyDataTemplate.InstantiateIn(this);
				}
				
				return 0;
			}

			WebControl container = null;

			if (!string.IsNullOrEmpty(Title)) {
				var titleBar = new WebControl(HtmlTextWriterTag.Div);
				titleBar.ApplyStyle(TitleBarStyle);

				var title = new WebControl(HtmlTextWriterTag.Div);
				title.ApplyStyle(TitleStyle);

				var titleLiteral = new Literal();
				titleLiteral.Text = Title;
				titleLiteral.Mode = LiteralMode.Encode;
				title.Controls.Add(titleLiteral);
				titleBar.Controls.Add(title);

				Controls.Add(titleBar);

				container = new WebControl(HtmlTextWriterTag.Div);
				container.ApplyStyle(ContentStyle);
			} else {
				ApplyStyle(ContentStyle);
			}

			m_dataItem = enumerator.Current;

			if (container == null) {
				ContentTemplate.InstantiateIn(this);
			} else {
				ContentTemplate.InstantiateIn(container);
				Controls.Add(container);
			}

			if (dataBinding) {
				DataBind(false);
			}

			return 1;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="data"></param>
		protected override void PerformDataBinding(IEnumerable data) {
			base.PerformDataBinding(data);
			if ((base.IsBoundUsingDataSourceID && base.IsViewStateEnabled)) {
				m_boundFields = new OrderedDictionary();
				this.ExtractRowValues(m_boundFields, false);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		protected override object SaveViewState() {
			object obj = base.SaveViewState();
			object titleBarStyle = ((IStateManager)TitleBarStyle).SaveViewState();
			object titleStyle = ((IStateManager)TitleStyle).SaveViewState();
			object contentStyle = ((IStateManager)ContentStyle).SaveViewState();
			object boundFields = (m_boundFields != null) ? SaveViewState(m_boundFields) : null;
			object controlStyle = ControlStyleCreated ? ((IStateManager)ControlStyle).SaveViewState() : null;
			return new object[] { obj, titleBarStyle, titleStyle, contentStyle, boundFields, controlStyle };
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="savedState"></param>
		protected override void LoadViewState(object savedState) {
			if (savedState != null) {
				object[] objArray = (object[])savedState;
				base.LoadViewState(objArray[0]);
				if (objArray[1] != null) {
					((IStateManager)TitleBarStyle).LoadViewState(objArray[1]);
				}
				if (objArray[2] != null) {
					((IStateManager)TitleStyle).LoadViewState(objArray[2]);
				}
				if (objArray[3] != null) {
					((IStateManager)ContentStyle).LoadViewState(objArray[3]);
				}
				if (objArray[4] != null) {
					m_boundFields = new OrderedDictionary();
					LoadViewState(m_boundFields, (List<Pair>)objArray[4]);
				}
				if (objArray[5] != null) {
					((IStateManager)base.ControlStyle).LoadViewState(objArray[5]);
				}
			} else {
				base.LoadViewState(null);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		protected override void TrackViewState() {
			base.TrackViewState();
			((IStateManager)TitleBarStyle).TrackViewState();
			((IStateManager)TitleStyle).TrackViewState();
			((IStateManager)ContentStyle).TrackViewState();
			if (ControlStyleCreated) {
				((IStateManager)base.ControlStyle).TrackViewState();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		protected override object SaveControlState() {
			object obj = base.SaveControlState();
			if ((obj == null) && ((this.m_dataKeyNames == null) || (this.m_dataKeyNames.Length <= 0)) && ((this.m_keyTable == null) || (this.m_keyTable.Count <= 0))) {
				return true;
			}
			object obj1 = null;
			object obj2 = null;
			if ((this.m_dataKeyNames != null) && (this.m_dataKeyNames.Length > 0)) {
				obj1 = this.m_dataKeyNames;
			}
			if (this.m_keyTable != null) {
				obj2 = SaveViewState(this.m_keyTable);
			}
			return new object[] { obj, obj1, obj2 };

		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="savedState"></param>
		protected override void LoadControlState(object savedState) {
			this.m_dataKeyNames = new string[0];
			object[] objArray = savedState as object[];
			if (objArray != null) {
				base.LoadControlState(objArray[0]);
				if (objArray[1] != null) {
					this.m_dataKeyNames = (string[])objArray[2];
				}
				if (objArray[2] != null) {
					this.KeyTable.Clear();
					LoadViewState(this.KeyTable, (List<Pair>)objArray[3]);
				}
			} else {
				base.LoadControlState(null);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="s1"></param>
		/// <param name="s2"></param>
		/// <returns></returns>
		private static bool CompareStringArrays(string[] s1, string[] s2) {
			if ((s1 != null) || (s2 != null)) {
				if ((s1 == null) || (s2 == null)) {
					return false;
				}
				if (s1.Length != s2.Length) {
					return false;
				}
				for (int i = 0; i < s1.Length; i++) {
					if (!string.Equals(s1[i], s2[i], StringComparison.Ordinal)) {
						return false;
					}
				}
			}
			return true;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dictionary"></param>
		/// <returns></returns>
		private static List<Pair> SaveViewState(IOrderedDictionary dictionary) {
			if (dictionary == null) {
				throw new ArgumentNullException("dictionary");
			}
			var list = new List<Pair>(dictionary.Count);
			foreach (DictionaryEntry entry in dictionary) {
				list.Add(new Pair(entry.Key, entry.Value));
			}
			return list;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dictionary"></param>
		/// <param name="state"></param>
		private static void LoadViewState(IOrderedDictionary dictionary, List<Pair> state) {
			if (dictionary == null) {
				throw new ArgumentNullException("dictionary");
			}
			if (state == null) {
				throw new ArgumentNullException("state");
			}
			if (state != null) {
				foreach (var pair in state) {
					dictionary.Add(pair.First, pair.Second);
				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="dictionary"></param>
		/// <param name="container"></param>
		private static void ExtractValuesFromBindableControls(IOrderedDictionary dictionary, Control container) {
			IBindableControl control = container as IBindableControl;
			if (control != null) {
				control.ExtractValues(dictionary);
			}
			foreach (Control control2 in container.Controls) {
				ExtractValuesFromBindableControls(dictionary, control2);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="fieldValues"></param>
		/// <param name="includeKeys"></param>
		protected virtual void ExtractRowValues(IOrderedDictionary fieldValues, bool includeKeys) {
			if (fieldValues != null) {
				ExtractValuesFromBindableControls(fieldValues, this);

				var itemTemplate = ContentTemplate as IBindableTemplate;

				if (itemTemplate != null) {
					string[] dataKeyNamesInternal = this.DataKeyNamesInternal;

					foreach (DictionaryEntry entry in itemTemplate.ExtractValues(this)) {
						if (entry.Key == null)
							continue;
						var key = entry.Key.ToString();

						if (includeKeys || !dataKeyNamesInternal.Contains(key)) {
							fieldValues[key] = entry.Value;
						}
					} // end of foreach.
				} // end of if.
			} // end of if.
		} // end of ExtractRowValue.

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandArg"></param>
		/// <param name="causesValidation"></param>
		private void HandleSave(string commandArg, bool causesValidation) {
			if ((!causesValidation || (this.Page == null)) || this.Page.IsValid) {

				DataSourceView data = null;
				bool isBoundUsingDataSourceID = base.IsBoundUsingDataSourceID;
				if (isBoundUsingDataSourceID) {
					data = this.GetData();
					if (data == null) {
						throw new HttpException(string.Format("Cannot retreive data from {0}.", DataSourceID));
					}
				}

				MyFormViewSaveEventArgs e = new MyFormViewSaveEventArgs(commandArg);

				if (m_boundFields != null) {
					foreach (DictionaryEntry entry in m_boundFields) {
						e.OldValues.Add(entry.Key, entry.Value);
					}
				}

				this.ExtractRowValues(e.NewValues, true);
				if (!string.IsNullOrEmpty(commandArg)) {
					e.NewValues["saveArgument"] = commandArg;
				}

				this.OnSaving(e);

				if (!e.Cancel && isBoundUsingDataSourceID) {
					try {
						CascadedChildren(ctl => ctl.Saving(e.NewValues, e.OldValues));
					} catch (Exception ex) {
						var e2 = CreateErrorEventArguments(ex, false);

						if (!e2.ExceptionHandled) {
							// Error has not been handled.
							m_logger.Warn("Failed to save data.", e2.Exception);
							return;
						}
					}

					this.m_saveKeys = e.Keys;
					this.m_saveOldValues = e.OldValues;
					this.m_saveNewValues = e.NewValues;
					data.Update(e.Keys, e.NewValues, e.OldValues, new DataSourceViewOperationCallback(this.HandleSaveCallback));
				}
			}
		} // end of HandleSave.

		/// <summary>
		/// 
		/// </summary>
		/// <param name="ex"></param>
		/// <param name="handleApplicationException"></param>
		/// <returns></returns>
		private MyFormViewErrorEventArgs CreateErrorEventArguments(Exception ex, bool handleApplicationException = true) {
			// Find root exception.
			var rex = ex;

			while (rex.InnerException != null)
				rex = rex.InnerException;

			var e2 = new MyFormViewErrorEventArgs(rex);

			if (rex is System.ApplicationException) {
				var fmt = ErrorMessageFormat;
				if (string.IsNullOrEmpty(fmt))
					fmt = Properties.Main.ErrorSave;

				Context.AddError(fmt, rex.Message);

				e2.ExceptionHandled = handleApplicationException;
			}

			OnError(e2);

			return e2;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="affectedRows"></param>
		/// <param name="ex"></param>
		/// <returns></returns>
		private bool HandleSaveCallback(int affectedRows, Exception ex) {
			if (ex != null) {
				var e = CreateErrorEventArguments(ex);

				this.m_saveKeys = null;
				this.m_saveOldValues = null;
				this.m_saveNewValues = null;

				if (!e.ExceptionHandled) {
					// Error has not been handled.
					m_logger.Warn("Failed to save data.", e.Exception);
					return false;
				}
			} else {
				var e = new MyFormViewSavedEventArgs(affectedRows);
				e.SetOldValues(this.m_saveOldValues);
				e.SetNewValues(this.m_saveNewValues);
				e.SetKeys(this.m_saveKeys);

				this.m_saveKeys = null;
				this.m_saveOldValues = null;
				this.m_saveNewValues = null;

				try {
					CascadedChildren(ctl => ctl.Save(e.OldValues, e.NewValues));
				} catch (Exception ex2) {
					var e2 = CreateErrorEventArguments(ex2);

					if (!e2.ExceptionHandled) {
						// Error has not been handled.
						m_logger.Warn("Failed to save data.", e2.Exception);
						return false;
					}
				}

				this.RequiresDataBinding = true;

				this.OnSaved(e);
			}

			return true;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="processor"></param>
		private void CascadedChildren(Action<ICascadedControl> processor) {
			if (Controls == null || Controls.Count == 0)
				return;

			var q = new Queue<Control>();

			foreach (Control ctl in Controls)
				q.Enqueue(ctl);

			while (q.Count != 0) {
				var ctl = q.Dequeue();

				if (ctl is ICascadedControl) {
					var cctl = ctl as ICascadedControl;

					if (cctl != null)
						processor(cctl);
				} else {
					if (ctl.Controls == null)
						continue;

					if (ctl.Controls.Count == 0)
						continue;

					foreach (Control ctl2 in ctl.Controls)
						q.Enqueue(ctl2);
				}
			} // end of while.
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		/// <returns></returns>
		private bool HandleCommand(MyFormViewCommandEventArgs e) {
			return OnCommand(e);
		}

		/// <summary>
		/// 
		/// </summary>
		private void HandleReset() {
			RequiresDataBinding = true;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		private void HandleCancel(MyFormViewCommandEventArgs e) {
			RequiresDataBinding = true;
			OnCancelled(e);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		/// <param name="causesValidation"></param>
		/// <param name="validationGroup"></param>
		/// <returns></returns>
		private bool HandleEvent(EventArgs e, bool causesValidation, string validationGroup) {
			MyFormViewCommandEventArgs args = e as MyFormViewCommandEventArgs;
			if (args == null) {
				return false;
			}

			string commandName = args.CommandName;

			if (string.Equals(commandName, "Save", StringComparison.OrdinalIgnoreCase)) {
				this.HandleSave((string)args.CommandArgument, causesValidation);
				return true;
			} else if (string.Equals(commandName, "Reset", StringComparison.OrdinalIgnoreCase)) {
				this.HandleReset();
				return true;
			} else if (string.Equals(commandName, "Cancel", StringComparison.OrdinalIgnoreCase)) {
				this.HandleCancel(args);
				return true;
			} else {
				return HandleCommand(args);
			}
		} // end of HandleEvent.

		/// <summary>
		/// 
		/// </summary>
		/// <param name="eventArgument"></param>
		protected virtual void RaisePostBackEvent(string eventArgument) {
			int index = eventArgument.IndexOf('$');
			if (index >= 0) {
				CommandEventArgs originalArgs = new CommandEventArgs(eventArgument.Substring(0, index), eventArgument.Substring(index + 1));
				MyFormViewCommandEventArgs e = new MyFormViewCommandEventArgs(this, originalArgs);
				this.HandleEvent(e, false, string.Empty);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="source"></param>
		/// <param name="e"></param>
		/// <returns></returns>
		protected override bool OnBubbleEvent(object source, EventArgs e) {
			bool causesValidation = false;
			string validationGroup = string.Empty;

			if (e is CommandEventArgs) {
				MyFormViewCommandEventArgs args = new MyFormViewCommandEventArgs(source, (CommandEventArgs)e);

				IButtonControl commandSource = args.CommandSource as IButtonControl;
				if (commandSource != null) {
					causesValidation = commandSource.CausesValidation;
					validationGroup = commandSource.ValidationGroup;
				}

				return this.HandleEvent(args, causesValidation, validationGroup);
			} else {
				return false;
			}
		}

		#region IPostBackEventHandler

		/// <summary>
		/// 
		/// </summary>
		/// <param name="eventArgument"></param>
		void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) {
			RaisePostBackEvent(eventArgument);
		}

		#endregion

		#region IPostBackContainer

		/// <summary>
		/// 
		/// </summary>
		/// <param name="buttonControl"></param>
		/// <returns></returns>
		PostBackOptions IPostBackContainer.GetPostBackOptions(IButtonControl buttonControl) {
			if (buttonControl == null) {
				throw new ArgumentNullException("buttonControl");
			}
			PostBackOptions options = new PostBackOptions(this, buttonControl.CommandName + "$" + buttonControl.CommandArgument);
			options.RequiresJavaScriptProtocol = true;
			return options;
		}

		#endregion

		/// <summary>
		/// 
		/// </summary>
		public event EventHandler<MyFormViewCommandEventArgs> Command;

		/// <summary>
		/// 
		/// </summary>
		public event EventHandler<MyFormViewSaveEventArgs> Saving;

		/// <summary>
		/// 
		/// </summary>
		public event EventHandler<MyFormViewSavedEventArgs> Saved;

		/// <summary>
		/// 
		/// </summary>
		public event EventHandler<MyFormViewCommandEventArgs> Cancelled;

		/// <summary>
		/// 
		/// </summary>
		public event EventHandler<MyFormViewErrorEventArgs> Error;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		/// <returns></returns>
		protected virtual bool OnCommand(MyFormViewCommandEventArgs e) {
			if (Command != null) {
				Command(this, e);
				return true;
			} else {
				return false;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnSaving(MyFormViewSaveEventArgs e) {
			if (Saving != null) {
				Saving(this, e);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnSaved(MyFormViewSavedEventArgs e) {
			if (Saved != null) {
				Saved(this, e);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnCancelled(MyFormViewCommandEventArgs e) {
			if (Cancelled != null) {
				Cancelled(this, e);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected virtual void OnError(MyFormViewErrorEventArgs e) {
			if (Error != null) {
				Error(this, e);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public object DataItem {
			get { return this.m_dataItem; }
		}

		/// <summary>
		/// 
		/// </summary>
		public int DataItemIndex {
			get { return 0; }
		}

		/// <summary>
		/// 
		/// </summary>
		public int DisplayIndex {
			get { return 0; }
		}

		#region IDataItemContainer

		object IDataItemContainer.DataItem {
			get { return DataItem; }
		}

		int IDataItemContainer.DataItemIndex {
			get { return DataItemIndex; }
		}

		int IDataItemContainer.DisplayIndex {
			get { return DisplayIndex; }
		}

		#endregion

		/// <summary>
		/// 
		/// </summary>
		[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
		Description("MyPanel_DataKey"),
		Browsable(false)]
		public virtual DataKey DataKey {
			get {
				if (this.m_dataKey == null) {
					this.m_dataKey = new DataKey(this.KeyTable);
				}
				return this.m_dataKey;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		[DefaultValue((string)null),
		Description("DataControls_DataKeyNames"),
			// Editor(typeof(System.Web.UI.Design.WebControls.DataFieldEditor), typeof(UITypeEditor)),
		TypeConverter(typeof(StringArrayConverter)),
		Category("Data")]
		public virtual string[] DataKeyNames {
			get {
				if (this.m_dataKeyNames != null) {
					return (string[])this.m_dataKeyNames.Clone();
				}
				return new string[0];
			}
			set {
				if (!CompareStringArrays(value, this.DataKeyNamesInternal)) {
					if (value != null) {
						this.m_dataKeyNames = (string[])value.Clone();
					} else {
						this.m_dataKeyNames = null;
					}
					this.m_keyTable = null;
					if (this.Initialized) {
						this.RequiresDataBinding = true;
					}
				}
			}
		}

		#region IDataBoundItemControl

		string[] IDataBoundControl.DataKeyNames {
			get {
				return this.DataKeyNames;
			}
			set {
				this.DataKeyNames = value;
			}
		}

		string IDataBoundControl.DataMember {
			get {
				return this.DataMember;
			}
			set {
				this.DataMember = value;
			}
		}

		object IDataBoundControl.DataSource {
			get {
				return this.DataSource;
			}
			set {
				this.DataSource = value;
			}
		}

		string IDataBoundControl.DataSourceID {
			get {
				return this.DataSourceID;
			}
			set {
				this.DataSourceID = value;
			}
		}

		IDataSource IDataBoundControl.DataSourceObject {
			get {
				return base.DataSourceObject;
			}
		}

		DataKey IDataBoundItemControl.DataKey {
			get {
				return this.DataKey;
			}
		}

		DataBoundControlMode IDataBoundItemControl.Mode {
			get {
				return DataBoundControlMode.Edit;
			}
		}

		#endregion
	} // end of MyFormView.

	/// <summary>
	/// 
	/// </summary>
	public class MyFormViewCommandEventArgs : CommandEventArgs {
		/// <summary>
		/// 
		/// </summary>
		public object CommandSource { get; private set; }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandSource"></param>
		/// <param name="originalArgs"></param>
		public MyFormViewCommandEventArgs(object commandSource, CommandEventArgs originalArgs)
			: base(originalArgs) {
			CommandSource = commandSource;
		}
	} // end of MyPanelCommandEventArgs.

	/// <summary>
	/// 
	/// </summary>
	public class MyFormViewSaveEventArgs : CancelEventArgs {
		// Fields
		private object m_commandArgument;
		private OrderedDictionary m_keys;
		private OrderedDictionary m_oldValues;
		private OrderedDictionary m_values;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="commandArgument"></param>
		public MyFormViewSaveEventArgs(object commandArgument)
			: base(false) {
			this.m_commandArgument = commandArgument;
		}

		/// <summary>
		/// 
		/// </summary>
		public object CommandArgument {
			get {
				return this.m_commandArgument;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public IOrderedDictionary Keys {
			get {
				if (this.m_keys == null) {
					this.m_keys = new OrderedDictionary();
				}
				return this.m_keys;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public IOrderedDictionary NewValues {
			get {
				if (this.m_values == null) {
					this.m_values = new OrderedDictionary();
				}
				return this.m_values;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public IOrderedDictionary OldValues {
			get {
				if (this.m_oldValues == null) {
					this.m_oldValues = new OrderedDictionary();
				}
				return this.m_oldValues;
			}
		}
	} // end of MyPanelSaveEventArgs.

	/// <summary>
	/// 
	/// </summary>
	public class MyFormViewSavedEventArgs : EventArgs {
		// Fields
		private int m_affectedRows;
		private IOrderedDictionary m_keys;
		private IOrderedDictionary m_oldValues;
		private IOrderedDictionary m_values;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="affectedRows"></param>
		public MyFormViewSavedEventArgs(int affectedRows) {
			this.m_affectedRows = affectedRows;
		}

		internal void SetKeys(IOrderedDictionary keys) {
			this.m_keys = keys;
		}

		internal void SetNewValues(IOrderedDictionary newValues) {
			this.m_values = newValues;
		}

		internal void SetOldValues(IOrderedDictionary oldValues) {
			this.m_oldValues = oldValues;
		}

		/// <summary>
		/// 
		/// </summary>
		public int AffectedRows {
			get {
				return this.m_affectedRows;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public IOrderedDictionary Keys {
			get {
				if (this.m_keys == null) {
					this.m_keys = new OrderedDictionary();
				}
				return this.m_keys;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public IOrderedDictionary NewValues {
			get {
				if (this.m_values == null) {
					this.m_values = new OrderedDictionary();
				}
				return this.m_values;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public IOrderedDictionary OldValues {
			get {
				if (this.m_oldValues == null) {
					this.m_oldValues = new OrderedDictionary();
				}
				return this.m_oldValues;
			}
		}
	} // end of MyPanelSavedEventArgs.

	/// <summary>
	/// 
	/// </summary>
	public class MyFormViewErrorEventArgs : EventArgs {
		// Fields
		private Exception m_exception;
		private bool m_exceptionHandled;

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		public MyFormViewErrorEventArgs(Exception e) {
			this.m_exceptionHandled = false;
			this.m_exception = e;
		}

		/// <summary>
		/// 
		/// </summary>
		public Exception Exception {
			get {
				return this.m_exception;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public bool ExceptionHandled {
			get {
				return this.m_exceptionHandled;
			}
			set {
				this.m_exceptionHandled = value;
			}
		}
	} // end of MyPanelUpdatedEventArgs.
}
